/**
 * @Author: lena
 * @Description:
 * @Version: 1.0.0
 * @Date: 2021/8/25 15:30
 */

package datatype

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// type的作用就相当于为某一类型起别名
// 为int起别名intint
type intint int

func Struct1() {
	// 使用intint定义的数据类型 实际上是int型
	var a intint
	fmt.Println(a)
}

// 定义一个student结构体
type student struct {
	sid  int
	name string
}

func Struct2() {
	var student1 student
	// 为结构体赋值
	student1.sid = 1001
	student1.name = "lena"
	fmt.Println(student1) // {1001 lena}
}

func method5(student1 student) {
	// 实际使用的是副本
	student1.sid = 7777
}

func Struct3() {
	var student1 student
	// 为结构体赋值
	student1.sid = 1001
	student1.name = "lena"
	fmt.Println(student1) // {1001 lena}
	method5(student1)
	// 值没有改变，说明是值传递
	fmt.Println(student1) // {1001 lena}
}

func method6(student1 *student) {
	// 引用传递：传递的是实际地址
	student1.sid = 7777
}

func Struct4() {
	var student1 student
	// 为结构体赋值
	student1.sid = 1001
	student1.name = "lena"
	fmt.Println(student1) // {1001 lena}
	method6(&student1)
	// 值改变了
	fmt.Println(student1) // {7777 lena}
}

// 结构体标签：利用反引号以key:"value"形式
type structTag struct {
	Name string `info:"name" doc:"名字"`
	Sex  string `info:"sex" doc:"性别"`
}

func findTag(tag interface{}) {
	// 利用反射获取标签内容
	t := reflect.TypeOf(tag).Elem()
	for i := 0; i < t.NumField(); i++ {
		info := t.Field(i).Tag.Get("info") // 标签info的值
		doc := t.Field(i).Tag.Get("doc")   // 标签doc的值
		fmt.Println(info, doc)             // name 名字
	}
}

func Struct5() {
	tag := structTag{"hello", "women"}
	findTag(&tag)
}

// Struct6 匿名结构体
func Struct6() {
	var s struct {
		id   int
		name string
	}
	s.id = 1001
	s.name = "lena"
	fmt.Println(s) // {1001 lena}
}

// golang传递是值传递,但对于引用类型,值为地址值,因此无需使用指针也会改变
type manager struct {
	id       int
	name     string
	power    []string
	relation map[string]int
}

func (this manager) changeRelation(s string, phone int) {
	maps := this.relation // 真实改变了
	maps[s] = phone
}

func (this manager) addPower1(s string) {
	ps := this.power // 没改变
	ps = append(ps, s)
}

func (this manager) addPower2(s string) {
	ps := this.power // 没改变
	this.power = append(ps, s)
}

func (this *manager) addPower3(s string) {
	ps := this.power // 改变了
	this.power = append(ps, s)
}

func (this manager) changeId1(id int) {
	this.id = id // 值传递 改变的是副本 实际值没有改变
}

func (this *manager) changeId2(id int) {
	this.id = id // 改变地址的值
}

func Struct7() {
	m := manager{
		id:    1001,
		name:  "hello",
		power: []string{"开门", "关门", "取文件"},
		relation: map[string]int{
			"母亲":  10086,
			"父亲":  10086,
			"合租人": 10086,
		},
	}
	fmt.Println(m) // {1001 hello [开门 关门 取文件] map[合租人:10086 母亲:10086 父亲:10086]}
	m.changeRelation("母亲", 11111)
	fmt.Println(m.relation) // map[合租人:10086 母亲:11111 父亲:10086]
	m.addPower1("删文件")
	fmt.Println(m.power) // [开门 关门 取文件]
	m.addPower2("删文件")
	fmt.Println(m.power) // [开门 关门 取文件]
	m.addPower3("删文件")
	fmt.Println(m.power) // [开门 关门 取文件 删文件]
	m.changeId1(1)
	fmt.Println(m.id) // 1001
	m.changeId2(2)
	fmt.Println(m.id) // 2
}

// Struct8 结构体会自己初始化零值,没有初始化值的时候可以不写,或者可以初始化部分值
func Struct8() {
	m := manager{}
	fmt.Println(m) // {0  [] map[]}
	m1 := manager{id: 100}
	fmt.Println(m1) // {100  [] map[]}
}

// 结构体的构造函数
func newManger(id int, name string) manager {
	return manager{
		id:   id,
		name: name,
	}
}

// Struct9 结构体是值传递 不同结构体之间互不影响
func Struct9() {
	s1 := student{1001, "lena"}
	fmt.Println(s1) // {1001 lena}
	s2 := s1
	fmt.Println(s2) // {1001 lena}
	s2.sid = 4
	s2.name = "仲恺农业工程学院"
	fmt.Println(s2) // {4 仲恺农业工程学院}
	fmt.Println(s1) // {1001 lena}
}

// omitempty关键字 学习
type response1 struct {
	Code    int      `json:"code,omitempty"`
	Messgae string   `json:"messgae"`
	Time    string   `json:"time"`
	Result  student1 `json:"return,omitempty"`
}
type student1 struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func Struct10() {
	// 若传入的值是默认空值 则会被忽略 如code是int型 默认空值是0 所以code在json转换的时候会被忽略
	res1 := response1{0, "success", "2022-02-18", student1{"lena", 20}}
	m1, _ := json.Marshal(res1)
	fmt.Println("m1", string(m1)) // {"messgae":"success","time":"2022-02-18","return":{"name":"lena","age":20}}
	// 若是结构体类型 空结构体也不会被忽略 如student1没有传入值 但是json转换的时候还是会显示空的student1 因为Go无法区分结构体如何为空
	res2 := response1{Code: 200, Messgae: "success", Time: "2022-02-18"}
	m2, _ := json.Marshal(res2)
	fmt.Println("m2", string(m2)) // {"code":200,"messgae":"success","time":"2022-02-18","return":{"name":"","age":0}}
}

type response2 struct {
	Code    int       `json:"code,omitempty"`
	Messgae string    `json:"messgae"`
	Time    string    `json:"time,omitempty"`
	Result  *student2 `json:"return,omitempty"`
}
type student2 struct {
	Name string `json:"name,omitempty"`
	Age  int    `json:"age,omitempty"`
}

func Struct11() {
	// 结构体内嵌的结构体 改用了指针类型 指针的默认空值是nil 因此如果我们没传入 就不会显示
	res1 := response2{Code: 200, Messgae: "success", Time: "2022-02-18"}
	m1, _ := json.Marshal(res1)
	fmt.Println("m1", string(m1)) // m1 {"code":200,"messgae":"success","time":"2022-02-18"}
	// 指定omitempty没传入值 转json就不显示
	res2 := response2{Code: 200, Messgae: "success", Result: &student2{"lena", 12}}
	m2, _ := json.Marshal(res2)
	fmt.Println("m2", string(m2)) // m2 {"code":200,"messgae":"success","return":{"name":"lena","age":12}}
}
